package com.yict.csms.system.service.impl;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pccw.portlet.util.excel.importutil.ExcelImporter;
import com.pccw.portlet.util.excel.importutil.ImportedExcelData;
import com.yict.common.entity.PageEntity;
import com.yict.common.service.impl.BaseServiceImpl;
import com.yict.common.util.ObjectUtil;
import com.yict.csms.baseInfo.entity.ContractType;
import com.yict.csms.baseInfo.service.impl.ContractTypeServiceImpl;
import com.yict.csms.company.entity.Company;
import com.yict.csms.company.entity.ContractRate;
import com.yict.csms.company.service.impl.CompanyServiceImpl;
import com.yict.csms.company.service.impl.ContractRateServiceImpl;
import com.yict.csms.resourceplan.service.IBoxContractorService;
import com.yict.csms.resourceplan.service.IPersonOrderService;
import com.yict.csms.resourceplan.service.impl.RtgcFlOrderServiceImpl;
import com.yict.csms.system.dao.ICostDao;
import com.yict.csms.system.dao.ICostProfessionDao;
import com.yict.csms.system.entity.BudgetNum;
import com.yict.csms.system.entity.Cost;
import com.yict.csms.system.entity.CostProfession;
import com.yict.csms.system.entity.DataDict;
import com.yict.csms.system.entity.ExchangeRate;
import com.yict.csms.system.entity.Profession;
import com.yict.csms.system.entity.Station;
import com.yict.csms.system.entity.User;
import com.yict.csms.system.service.ICostService;
import com.yict.csms.system.service.IDataDictService;
import com.yict.csms.system.service.IExchangeRateService;
import com.yict.csms.system.service.IProfessionService;
import com.yict.csms.system.service.IStationService;
import com.yict.csms.system.util.DictionaryUtils;

@Service("costService")
public class CostServiceImpl extends BaseServiceImpl<Cost, Long, ICostDao>
		implements ICostService {
	private static Log logger = LogFactory.getLog(CostServiceImpl.class);
	private IDataDictService dictService;
	private CompanyServiceImpl companyService;
	private IProfessionService professionService;
	private IStationService stationService;
	private ICostProfessionDao costProfessionDao;
	private ContractRateServiceImpl contractRateService;
	private IPersonOrderService personOrderService;
	private IExchangeRateService exchangeRateService;
	private RtgcFlOrderServiceImpl rtgcFlOrderService;
	private IBoxContractorService boxContractorService;
	private HolidayServiceImpl holidayService;
	private ContractTypeServiceImpl contractTypeService;
	private BudgetNumServiceImpl budgetNumService;

	@Override
	public boolean check(Date beginDate, Date endDate, DataDict dataDict,
			DataDict currency) {
		return this.getBaseDao().check(beginDate, endDate, dataDict, currency);
	}

	@Override
	public boolean check(BudgetNum budgetNum) {
		return this.getBaseDao().check(budgetNum);
	}

	/**
	 * 目前仅有麻鹰/龙门吊派更/雪箱派更/人员订更能使用本方法生成计费
	 * 
	 * @param companyid
	 *            公司的主键
	 * @param profeid
	 *            工种的主键
	 * @param stationid
	 *            岗位的主键,可以为null
	 * @param formid
	 *            派更确认记录的主键
	 * @param accountmethod
	 *            计费方式字典主键，参见字典类型ACCOUNTMETHOD,如果是雪箱、麻鹰、龙门吊、船舶则为空
	 * @param servicedate
	 *            服务日期即订更日期
	 * @param servicebegintime
	 *            开始时间，可以为null，如果为null则以该更次的开始时间为开始时间
	 * @param serviceendtime
	 *            结束时间，可以为null，如果为null则以该更次的结束时间为结束时间
	 * @param servicetime
	 *            更次，字典主键
	 * @param deductworkhour
	 *            扣除工时,小时数。可以为null
	 * @param deductreason
	 *            扣除工时的原因，可以为null
	 * @param quantity
	 *            数量，如果工种是按工作量计算的这里不为null值
	 * @param source
	 *            数据来源,数据字典主键，麻鹰/龙门吊派更/船舶操作/雪箱派更/人员订更/文件导入/录入，
	 *            参看数据字典type为COST_SOURCE
	 * @return true 操作成功,否则操作失败
	 */
	@Override
	// @Transactional(readOnly = false,rollbackFor={Exception.class})
	public boolean createCost(Long companyid, Long profeid, Long stationid,
			Long formid, String accountmethod, Date servicedate,
			Date servicebegintime, Date serviceendtime, String servicetime,
			BigDecimal deductworkhour, String deductreason,
			BigDecimal quantity, String source, User us) throws Exception {

		// if(formid == null) throw new Exception("没有派更确认数据");
		// if(servicedate == null) throw new Exception("没有订更日期");

		// 数据来源
		DataDict dsdict = dictService.findById(source);
		if (dsdict == null)
			throw new Exception("不明确的数据来源");
		// 全部都是有派更计费
		DataDict asdict = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_TYPE_01);
		if (asdict == null)
			throw new Exception("数据字典错误，没有计费来源类型");

		Company company = companyService.findById(companyid);
		if (company == null)
			throw new Exception("没有承包商");

		DataDict dict = dictService.findById(servicetime);
		if (dict != null
				&& DictionaryUtils.DICT_TYPE_TIME_BUCKET.equals(dict
						.getDatatype())) {

			String[] timeRange = dict.getDatavalue().split("\\-");
			String startTime = timeRange[0];
			String endTime = timeRange[1];
			String[] stPart = startTime.split(":");
			String[] edPart = endTime.split(":");
			int stH = Integer.parseInt(stPart[0]);
			int stM = Integer.parseInt(stPart[1]);
			int edH = Integer.parseInt(edPart[0]);
			int edM = Integer.parseInt(edPart[1]);

			Calendar calendar = Calendar.getInstance();
			calendar.setTime(servicedate);
			if (servicebegintime == null) {
				calendar.set(Calendar.HOUR_OF_DAY, stH);
				calendar.set(Calendar.MINUTE, stM);
				calendar.set(Calendar.SECOND, 0);
				servicebegintime = calendar.getTime();
			}
			if (serviceendtime == null) {
				calendar.set(Calendar.HOUR_OF_DAY, edH);
				calendar.set(Calendar.MINUTE, edM);
				calendar.set(Calendar.SECOND, 0);
				calendar.add(Calendar.MINUTE, 1);
				serviceendtime = calendar.getTime();
			}
		}

		// 总工时数
		BigDecimal awh = new BigDecimal(0);
		BigDecimal workhour = new BigDecimal(0);
		if (deductworkhour == null)
			deductworkhour = new BigDecimal(0);
		if (serviceendtime != null && servicebegintime != null) {
			awh = new BigDecimal(
					(serviceendtime.getTime() - servicebegintime.getTime()) / 1000d / 60 / 60);
			workhour = awh;
		}

		BigDecimal allWorkQuantity;

		DataDict amdict = dictService
				.findByCode(DictionaryUtils.DICT_CODE_ACCOUNTMETHOD_2);
		if (DictionaryUtils.DICT_CODE_COST_SOURCE_1
				.equals(dsdict.getDatacode())) {
			accountmethod = amdict.getDictid();
			allWorkQuantity = quantity;
		} else if (DictionaryUtils.DICT_CODE_COST_SOURCE_2.equals(dsdict
				.getDatacode())) {
			accountmethod = amdict.getDictid();
			allWorkQuantity = quantity;
		} else if (DictionaryUtils.DICT_CODE_COST_SOURCE_4.equals(dsdict
				.getDatacode())) {
			accountmethod = amdict.getDictid();
			allWorkQuantity = quantity;
		} else if (DictionaryUtils.DICT_CODE_COST_SOURCE_3.equals(dsdict
				.getDatacode())) {
			accountmethod = amdict.getDictid();
			allWorkQuantity = quantity;
		} else {
			DataDict dict1 = dictService.findById(accountmethod);
			if (dict1 == null
					|| !DictionaryUtils.DICT_TYPE_ACCOUNTMETHOD.equals(dict1
							.getDatatype()))
				throw new Exception("没有计费方式");
			if (DictionaryUtils.DICT_CODE_ACCOUNTMETHOD_2.equals(dict1
					.getDatacode())) {
				allWorkQuantity = quantity;
			} else {
				allWorkQuantity = workhour.subtract(deductworkhour).multiply(
						quantity);
			}
		}

		Profession profession = professionService.findById(profeid);
		if (profession == null)
			throw new Exception("没有工种");

		// 有没有需要分解的下级工种，比如雪箱中pc+pti工种将分解为pc和pti两个工种
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("orderProfeid", profession);
		List<CostProfession> cplst = costProfessionDao.list(map, null, 0, 0);
		List<Profession> lp = new ArrayList<Profession>();
		if (cplst.size() > 0) {
			for (CostProfession c : cplst) {
				lp.add(c.getCostProfeid());
			}
		} else {
			lp.add(profession);
		}

		// 派更确认日期
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		Date confirmdate = calendar.getTime();
		
		//是否节假日
		boolean isHoliday = holidayService.checkHoliday(servicedate);

		//先按工种拆分计费
		for (Profession p : lp) {
			BigDecimal monthTotal = this.sumByMonth(companyid, p.getProfeid(), servicedate);
			BigDecimal thisTotal;
			if (!accountmethod.equals(amdict.getDictid())) {
				thisTotal = monthTotal.add(allWorkQuantity);
			} else
				thisTotal = monthTotal.add(quantity);

			List<ContractRate> rateList = contractRateService.queryRate(
					companyid, p.getProfeid(), servicedate, monthTotal);
			List<ContractRate> rateList2 = contractRateService.queryRate(
					companyid, p.getProfeid(), servicedate, thisTotal);
			if (rateList.size() == 0)
				throw new Exception("该承包商在工种" + p.getProfename() + "没有合同");
			rateList.remove(0);
			rateList2.removeAll(rateList);
			
			//按数量分段生成计费记录
			for(ContractRate rate : rateList2){
				BigDecimal startQuan = new BigDecimal(rate.getStartquan());
				if(startQuan.compareTo(monthTotal) < 0) startQuan = monthTotal;
				BigDecimal sectionNum = thisTotal.subtract(startQuan).setScale(3, BigDecimal.ROUND_HALF_UP);
				BigDecimal rateValue = new BigDecimal(rate.getRate()).setScale(3,BigDecimal.ROUND_HALF_UP);
				//节假日另加
				BigDecimal holidayAddtion = new BigDecimal(0) ;
				if(isHoliday) {
					holidayAddtion = new BigDecimal(rate.getAddforHoliday()).setScale(3,BigDecimal.ROUND_HALF_UP);
					rateValue.add(holidayAddtion);
				}
				
				Cost vo = new Cost();
				vo.setCompanyid(companyid);
				vo.setProfeid(p.getProfeid());
				vo.setStationid(stationid);
				vo.setSourceid(formid);
				vo.setAccountmethod(accountmethod);
				vo.setServicedate(servicedate);
				vo.setServicebegintime(servicebegintime);
				vo.setServiceendtime(serviceendtime);
				// vo.setServiceendtime(servicedate);
				vo.setServicetime(servicetime);
				vo.setDeductworkhour(deductworkhour);
				vo.setDeductreason(deductreason);
				if (!accountmethod.equals(amdict.getDictid())) {
					vo.setQuantity(quantity);
					vo.setAllworkhours(sectionNum);
				} else
					vo.setAllworkquantity(sectionNum);
				vo.setWorkhour(awh);
				vo.setSource(source);
				vo.setCreatedate(new Date());
				vo.setCreateperson(us.getUserId());
				vo.setCosttype(asdict.getDictid());
	
				if (rate.getContract() != null
						&& rate.getContract().getContractType() != null)
					vo.setTypeid(rate.getContract().getContractType().getTypeId());
				vo.setUnit(rate.getUnit());
				vo.setRatecurrency(rate.getCurrency());
				vo.setRate(rateValue);
				vo.setHolidayAdd(holidayAddtion);
				if (rate.getCheckNo() != null)
					vo.setCheckno(rate.getCheckNo());
				if (rate.getBudgetNum() != null)
					vo.setBudgetnum(rate.getBudgetNum().getNumId());
				vo.setConfirmdate(confirmdate);
				getBaseDao().save(vo);
	
				// 计费
				DataDict dict1 = dictService
						.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_2);
				DataDict dictRmb = dictService
						.findByCode(DictionaryUtils.DICT_CURRENCY_1);
				vo.setStatus(dict1.getDictid());
				vo.setCostdate(confirmdate);
				vo.setCostUser(us.getUserId());
				vo.setAllcurrency(dictRmb.getDictid());
				this.caculateFee(vo);
				
				//递减到下一个低级分段
				thisTotal = thisTotal.subtract(sectionNum);
			}
		}

		return true;
	}

	@Override
	@Transactional(readOnly = false, rollbackFor = { Exception.class })
	public boolean rejectAccount(Long[] ids, User us) throws Exception {
		// String hql = "from Cost c where c.costid in(:costids)";
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("costid", ids);
		List<Cost> lst = getBaseDao().list(map, null, 0, 0);
		Set<Cost> broderSet = new HashSet<Cost>();
		DataDict dictFl = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_1);
		DataDict dictRgtc = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_2);
		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_2);
		
		DataDict dictSource = dictService.findByCode(DictionaryUtils.DICT_CODE_COST_TYPE_01);
		for (Cost vo : lst) {
			if(!dictSource.getDictid().equals(vo.getCosttype())) 
				throw new Exception("只能返还有派更确认的记录！");

			// 检查状态
			if (!dict1.getDictid().equals(vo.getStatus()))
				throw new Exception("只能返还已计费状态的记录！");

			if (broderSet.contains(vo))
				continue;

			// 检查数据完整性，派更确认一条记录生成的多条计费记录需要一次返还
			Map<String, Object> map3 = new HashMap<String, Object>();// 麻鹰龙门吊
			if (dictFl.getDictid().equals(vo.getSource())
					|| dictRgtc.getDictid().equals(vo.getSource())) {
				map3.put("source", vo.getSource());
				map3.put("servicetime", vo.getServicetime());
				map3.put("servicedate", vo.getServicedate());
				map3.put("companyid", vo.getCompanyid());
			} else {// 雪箱，人员
				map3.put("source", vo.getSource());
				map3.put("sourceid", vo.getSourceid());
			}
			List<Cost> lst0 = getBaseDao().list(map3, null, 0, 0);
			broderSet.addAll(lst0);
		}
		broderSet.removeAll(lst);
		if (broderSet.size() > 0)
			throw new Exception("来源于同一条派更确认数据的计费记录必须一并返还");

		// 删除计费数据
		for (Cost vo : lst) {
			getBaseDao().remove(vo);
			DataDict dict = dictService.findById(vo.getSource());
			if (DictionaryUtils.DICT_CODE_COST_SOURCE_1.equals(dict
					.getDatacode())
					|| DictionaryUtils.DICT_CODE_COST_SOURCE_2.equals(dict
							.getDatacode())) {
				rtgcFlOrderService.costback(vo.getServicedate(),
						vo.getServicetime(), vo.getCompanyid(),
						dict.getDatacode());
			} else if (DictionaryUtils.DICT_CODE_COST_SOURCE_4.equals(dict
					.getDatacode())) {
				boxContractorService.backAssigned(vo.getSourceid(), us);
			} else if (DictionaryUtils.DICT_CODE_COST_SOURCE_5.equals(dict
					.getDatacode())) {
				Long[] sourceid = new Long[1];
				sourceid[0] = vo.getSourceid();
				personOrderService.reject2(sourceid, us.getUserId());
			}
		}

		return true;
	}

	@Override
	@Transactional(readOnly = false, rollbackFor = { Exception.class })
	public boolean cancelAccount(Long[] ids, User us) throws Exception {
		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_2);
		DataDict dict2 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_1);
		DataDict dictImp = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_6);
		DataDict dictIpu = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_7);
		// DictionaryUtils.DICT_CODE_COST_SOURCE_1
		Date taday = new Date();
		for (Long id : ids) {
			Cost vo = this.getBaseDao().findbyId(id);
			if (!dict1.getDictid().equals(vo.getStatus()))
				throw new Exception("数据状态不为" + dict1.getDisplayname());
			// 只能取消数据来源为导入或手工录入的记录
			if (!(dictImp.getDictid().equals(vo.getSource()) || dictIpu
					.getDictid().equals(vo.getSource())))
				throw new Exception("只能取消数据来源为导入或手工录入的记录的计费");
			vo.setStatus(dict2.getDictid());
			vo.setCostUser(null);
			vo.setCostdate(null);
			vo.setCancelCostDate(taday);
			vo.setCancelCostUser(us.getUserId());
			vo.setUpdateperson(us.getUserId());
			vo.setUpdatedate(taday);
			vo.setAllcost(null);
		}
		return true;
	}

	@Override
	@Transactional(readOnly = false, rollbackFor = { Exception.class })
	public boolean account(Long[] ids, User us) throws Exception {
		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_1);
		DataDict dict2 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_2);
		Date taday = new Date();
		for (Long id : ids) {
			Cost vo = this.getBaseDao().findbyId(id);
			if (!dict1.getDictid().equals(vo.getStatus()))
				throw new Exception("数据状态不为" + dict1.getDisplayname());
			vo.setStatus(dict2.getDictid());
			vo.setCostUser(us.getUserId());
			vo.setCostdate(taday);
			vo.setUpdateperson(us.getUserId());
			vo.setUpdatedate(taday);
			this.caculateFee(vo);
		}
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean confirmAccount(long[] ids, User us) throws Exception {
		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_2);
		DataDict dict2 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_3);
		Date taday = new Date();
		for (Long id : ids) {
			Cost vo = this.getBaseDao().findbyId(id);
			if (!dict1.getDictid().equals(vo.getStatus()))
				throw new Exception("数据状态不为" + dict1.getDisplayname());
			vo.setStatus(dict2.getDictid());
			vo.setCostconfirmperson(us.getUserId());
			vo.setCostConfirmDate(taday);
			vo.setUpdateperson(us.getUserId());
			vo.setUpdatedate(taday);
		}
		return true;
	}

	@Override
	public List<Cost> listForSheet(Map<String, Object> queryMap) {

		StringBuilder queryBuilder = new StringBuilder(
				"from Cost t where 1 = 1");
		Map<String, Object> map = new HashMap<String, Object>();

		String contractTypeIdList = (String) queryMap.get("contractTypeIdList");
		if (contractTypeIdList != null && contractTypeIdList.length() > 0) {
			String[] contractTypes = contractTypeIdList.split(",");
			if (contractTypes.length > 0) {
				Long[] contractTypesIds = new Long[contractTypes.length];
				for (int i = 0; i < contractTypes.length; i++)
					contractTypesIds[i] = ObjectUtil.s2l(contractTypes[i]);
				queryBuilder.append(" and typeid in (:typeid)");
				map.put("typeid", contractTypesIds);
			}
		}
		String checkno = (String) queryMap.get("checkno");
		if (checkno != null && checkno.length() > 0) {
			queryBuilder.append(" and checkno=:checkno");
			map.put("checkno", checkno);
		}
		String status = (String) queryMap.get("status");
		if (status != null && status.length() > 0) {
			queryBuilder.append(" and status=:status");
			map.put("status", status);
		}

		String companyid = (String) queryMap.get("companyid");
		if (companyid != null && companyid.length() > 0) {
			queryBuilder.append(" and companyid=:companyid");
			map.put("companyid", ObjectUtil.s2l(companyid));
		}

		String professionid = (String) queryMap.get("professionid");
		if (professionid != null && professionid.length() > 0) {
			queryBuilder.append(" and profeid=:profeid");
			map.put("profeid", ObjectUtil.s2l(professionid));
		}

		String budgetNumId = (String) queryMap.get("budgetNumId");
		if (budgetNumId != null && budgetNumId.length() > 0) {
			queryBuilder.append(" and budgetnum=:budgetnum");
			map.put("budgetnum", ObjectUtil.s2l(budgetNumId));
		}

		Date fromdate = (Date) queryMap.get("fromdate");
		Date todate = (Date) queryMap.get("todate");
		if (fromdate != null) {
			queryBuilder.append(" and servicedate>=:fromdate");
			map.put("fromdate", fromdate);
		}
		if (todate != null) {
			queryBuilder.append(" and servicedate<=:todate");
			map.put("todate", todate);
		}

		int count = getBaseDao().queryCount(
				"select count(*) " + queryBuilder.toString(), map);
		List<Cost> list;
		if (count > 0) {
			queryBuilder
					.append(" order by companyid, profeid, budgetnum, servicedate, rate ");
			list = getBaseDao().list(queryBuilder.toString(), map, 0, 0);
		} else {
			list = new ArrayList<Cost>();
		}

		return list;
	}

	@Override
	public List<Cost> list(Map<String, Object> queryMap, PageEntity page,
			LinkedHashMap<String, Boolean> orderList) {

		StringBuilder queryBuilder = new StringBuilder(
				"from Cost t where 1 = 1");
		Map<String, Object> map = new HashMap<String, Object>();

		String source = (String) queryMap.get("source");
		if (source != null && source.length() > 0) {
			queryBuilder.append(" and source=:source");
			map.put("source", source);
		}

		String checkno = (String) queryMap.get("checkno");
		if (checkno != null && checkno.length() > 0) {
			queryBuilder.append(" and checkno=:checkno");
			map.put("checkno", checkno);
		}

		String ratecurrency = (String) queryMap.get("ratecurrency");
		if (ratecurrency != null && ratecurrency.length() > 0) {
			queryBuilder.append(" and ratecurrency=:ratecurrency");
			map.put("ratecurrency", ratecurrency);
		}

		String status = (String) queryMap.get("status");
		if (status != null && status.length() > 0) {
			queryBuilder.append(" and status=:status");
			map.put("status", status);
		}

		String datatype = (String) queryMap.get("datatype");
		Date fromdate = (Date) queryMap.get("fromdate");
		Date todate = (Date) queryMap.get("todate");
		if ("servicedate".equals(datatype)) {
			if (fromdate != null) {
				queryBuilder.append(" and servicedate>=:fromdate");
				map.put("fromdate", fromdate);
			}
			if (todate != null) {
				queryBuilder.append(" and servicedate<=:todate");
				map.put("todate", todate);
			}
		} else if ("confirmdate".equals(datatype)) {
			if (fromdate != null) {
				queryBuilder.append(" and confirmdate>=:fromdate");
				map.put("fromdate", fromdate);
			}
			if (todate != null) {
				queryBuilder.append(" and confirmdate<=:todate");
				map.put("todate", todate);
			}
		} else if ("accountdate".equals(datatype)) {
			if (fromdate != null) {
				queryBuilder.append(" and costdate>=:fromdate");
				map.put("fromdate", fromdate);
			}
			if (todate != null) {
				queryBuilder.append(" and costdate<=:todate");
				map.put("todate", todate);
			}
		}

		String companyid = (String) queryMap.get("companyIdList");
		if (companyid != null && companyid.length() > 0) {
			String[] companyids = companyid.split(",");
			if (companyids.length > 0) {
				Long[] companyIds = new Long[companyids.length];
				for (int i = 0; i < companyids.length; i++)
					companyIds[i] = ObjectUtil.s2l(companyids[i]);
				queryBuilder.append(" and companyid in (:companyid)");
				map.put("companyid", companyIds);
			}
		}
		String profeidIdList = (String) queryMap.get("professionIdList");
		if (profeidIdList != null && profeidIdList.length() > 0) {
			String[] profeidIds = profeidIdList.split(",");
			if (profeidIds.length > 0) {
				Long[] profeidId = new Long[profeidIds.length];
				for (int i = 0; i < profeidIds.length; i++)
					profeidId[i] = ObjectUtil.s2l(profeidIds[i]);
				queryBuilder.append(" and profeid in (:profeid)");
				map.put("profeid", profeidId);
			}
		}
		String stationIdList = (String) queryMap.get("stationIdList");
		if (stationIdList != null && stationIdList.length() > 0) {
			String[] stationids = stationIdList.split(",");
			if (stationids.length > 0) {
				Long[] stationIds = new Long[stationids.length];
				for (int i = 0; i < stationids.length; i++)
					stationIds[i] = ObjectUtil.s2l(stationids[i]);
				queryBuilder.append(" and stationid in (:stationid)");
				map.put("stationid", stationIds);
			}
		}
		String contractTypeIdList = (String) queryMap.get("contractTypeIdList");
		if (contractTypeIdList != null && contractTypeIdList.length() > 0) {
			String[] contractTypes = contractTypeIdList.split(",");
			if (contractTypes.length > 0) {
				Long[] contractTypesIds = new Long[contractTypes.length];
				for (int i = 0; i < contractTypes.length; i++)
					contractTypesIds[i] = ObjectUtil.s2l(contractTypes[i]);
				queryBuilder.append(" and typeid in (:typeid)");
				map.put("typeid", contractTypesIds);
			}
		}
		String budgetNumIdList = (String) queryMap.get("budgetNumIdList");
		if (budgetNumIdList != null && budgetNumIdList.length() > 0) {
			String[] budgetNums = budgetNumIdList.split(",");
			if (budgetNums.length > 0) {
				Long[] budgetNumIds = new Long[budgetNums.length];
				for (int i = 0; i < budgetNums.length; i++)
					budgetNumIds[i] = ObjectUtil.s2l(budgetNums[i]);
				queryBuilder.append(" and budgetnum in (:budgetnum)");
				map.put("budgetnum", budgetNumIds);
			}
		}

		int count = getBaseDao().queryCount(
				"select count(*) " + queryBuilder.toString(), map);
		if (page != null)
			page.setTotalRecord(count);
		List<Cost> list;
		if (count > 0) {
			if (orderList == null) {
				orderList = new LinkedHashMap<String, Boolean>();
			}
			if (orderList.size() == 0)
				orderList.put("updatedate", false);
			StringBuilder orderString = new StringBuilder("");
			for (Map.Entry<String, Boolean> entry : orderList.entrySet()) {
				String key = entry.getKey();
				boolean value = entry.getValue();
				if (orderString.length() > 0)
					orderString.append(",");
				orderString.append(key);
				if (!value)
					orderString.append(" desc");
			}
			queryBuilder.append(" order by ").append(orderString);

			int startIndex = 0;
			int maxSize = 0;
			if (page != null) {
				startIndex = (page.getToPage() - 1) * page.getPageSize();
				maxSize = page.getPageSize();
			}
			list = getBaseDao().list(queryBuilder.toString(), map, startIndex,
					maxSize);
		} else {
			list = new ArrayList<Cost>();
		}

		return list;
	}

	@Override
	@Transactional(readOnly = false, rollbackFor = { Exception.class })
	public boolean save(List<Cost> list) throws Exception {
		for (Cost t : list) {
			List<ContractRate> list00 = contractRateService.listPersonOrder(
					t.getCompanyid(), t.getProfeid(), t.getServicedate());
			if (list00.size() == 0)
				throw new Exception("没有找到合同费率");
			if(list00.size() > 0){
				ContractRate rate = list00.get(0);
				t.setHolidayAdd((new BigDecimal(rate.getAddforHoliday())).setScale(3,BigDecimal.ROUND_HALF_UP));
			}
			getBaseDao().save(t);
		}
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean update(Cost t) throws Exception {
		if (t == null || t.getCostid() == null || t.getCostid().intValue() == 0)
			throw new Exception("无法获取更新数据!");
		Cost vo = getBaseDao().findbyId(t.getCostid());
		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_1);
		if (!dict1.getDictid().equals(vo.getStatus()))
			throw new Exception("只能编辑未计费的数据 ");
		List<ContractRate> list00 = contractRateService.listPersonOrder(
				t.getCompanyid(), t.getProfeid(), t.getServicedate());
		if (list00.size() == 0)
			throw new Exception("没有找到合同费率");

		if(list00.size() > 0){
			ContractRate rate = list00.get(0);
			t.setHolidayAdd((new BigDecimal(rate.getAddforHoliday())).setScale(3,BigDecimal.ROUND_HALF_UP));
		}
		
		vo.setCompanyid(t.getCompanyid());
		vo.setTypeid(t.getTypeid());
		vo.setProfeid(t.getProfeid());
		vo.setAccountmethod(t.getAccountmethod());
		vo.setStationid(t.getStationid());
		vo.setServicedate(t.getServicedate());
		vo.setServicebegintime(t.getServicebegintime());
		vo.setServiceendtime(t.getServiceendtime());
		vo.setServicetime(t.getServicetime());
		vo.setDeductworkhour(t.getDeductworkhour());
		vo.setDeductreason(t.getDeductreason());
		vo.setAllworkhours(t.getAllworkhours());
		vo.setQuantity(t.getQuantity());
		vo.setAllworkquantity(t.getAllworkquantity());
		vo.setRatecurrency(t.getRatecurrency());
		vo.setRate(t.getRate());
		vo.setUnit(t.getUnit());
		vo.setCheckno(t.getCheckno());
		vo.setBudgetnum(t.getBudgetnum());
		vo.setRemarks(t.getRemarks());
		vo.setHolidayAdd(t.getHolidayAdd());
		// vo.setCreatedate(t.getCreatedate());
		vo.setUpdateperson(t.getUpdateperson());
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean remove(Long[] ids) throws Exception {

		DataDict dict1 = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_1);
		DataDict dictImp = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_6);
		DataDict dictIpt = dictService
				.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_7);
		for (Long id : ids) {
			Cost cost = getBaseDao().findbyId(id);
			if (!dict1.getDictid().equals(cost.getStatus()))
				throw new Exception("只能删除未计费的数据！");
			if (!(dictImp.getDictid().equals(cost.getSource()) || dictIpt
					.getDictid().equals(cost.getSource())))
				throw new Exception("只能删除手工录入或文件导入的数据！");
		}
		return super.remove(ids);
	}

	@SuppressWarnings("rawtypes")
	@Override
	@Transactional(readOnly = false, rollbackFor = { Exception.class })
	public int importCost(String importFilePath, String templateFilePath)
			throws Exception {
		int importNum = 0;

		// 检测文件是否存在
		File importFile = new File(importFilePath);
		if (!importFile.exists())
			throw new Exception("数据导入失败，错误原因：文件找不到");

		ExcelImporter importer = new ExcelImporter(templateFilePath,
				importFilePath);
		if (importer.importExcel()) {
			ImportedExcelData importedData = importer.getImportedExcelData();

			// 工作表
			int sheetCount = importedData.getImportedSheetCount();
			// 默认数据
			DataDict sourceDict = dictService
					.findByCode(DictionaryUtils.DICT_CODE_COST_SOURCE_6);
			DataDict dict = dictService
					.findByCode(DictionaryUtils.DICT_CODE_COST_TYPE_02);
			DataDict dictStatus = dictService
					.findByCode(DictionaryUtils.DICT_CODE_COST_STATUS_1);
			DataDict dictRmb = dictService
					.findByCode(DictionaryUtils.DICT_CURRENCY_1);
			// 循环工作表
			for (int i = 0; i < sheetCount; i++) {
				// 获取行数据
				List sheetDetailLines = importedData.getDetailDataOfSheet(i);
				if (sheetDetailLines == null || sheetDetailLines.size() == 0)
					logger.info("当前工作表没数据");

				// 循环行数据
				for (int j = 0; sheetDetailLines != null
						&& j < sheetDetailLines.size(); j++) {
					Map lineData = (Map) sheetDetailLines.get(j);
					String accountmethodName = ObjectUtil.o2s(
							lineData.get("accountmethod")).trim();
					String companyName = ObjectUtil.o2s(
							lineData.get("companyid")).trim();
					String servicedateStr = ObjectUtil.o2s(
							lineData.get("servicedate")).trim();
					String servicebegintimeStr = ObjectUtil.o2s(
							lineData.get("servicebegintime")).trim();
					String serviceendtimeStr = ObjectUtil.o2s(
							lineData.get("serviceendtime")).trim();
					String contractTypeName = ObjectUtil.o2s(
							lineData.get("typeid")).trim();
					String profeName = ObjectUtil.o2s(lineData.get("profeid"))
							.trim();
					String stationName = ObjectUtil.o2s(
							lineData.get("stationid")).trim();
					String rateStr = ObjectUtil.o2s(lineData.get("rate"))
							.trim();
					String deductworkhourStr = ObjectUtil.o2s(
							lineData.get("deductworkhour")).trim();
					String deductreason = ObjectUtil.o2s(
							lineData.get("deductreason")).trim();
					String allworkquantityStr = ObjectUtil.o2s(
							lineData.get("allworkhours")).trim();
					String ratecurrencyName = ObjectUtil.o2s(
							lineData.get("ratecurrency")).trim();
					String unit = ObjectUtil.o2s(lineData.get("unit")).trim();
					String checknoName = ObjectUtil
							.o2s(lineData.get("checkno")).trim();
					String budgetnumName = ObjectUtil.o2s(
							lineData.get("budgetnum")).trim();
					String remarks = ObjectUtil.o2s(lineData.get("remarks"))
							.trim();

					BigDecimal rate = ObjectUtil.s2b(rateStr);
					BigDecimal deductworkhour = ObjectUtil
							.s2b(deductworkhourStr);
					BigDecimal allworkquantity = ObjectUtil
							.s2b(allworkquantityStr);
					Date servicedate = ObjectUtil.s2d(servicedateStr,
							"yyyy-MM-dd");
					if (servicedate == null)
						throw new Exception("服务时间错误");
					Date servicebegintime = ObjectUtil.s2d(servicedateStr + " "
							+ servicebegintimeStr, "yyyy-MM-dd HH:mm");
					Date serviceendtime = ObjectUtil.s2d(servicedateStr + " "
							+ serviceendtimeStr, "yyyy-MM-dd HH:mm");
					if (servicebegintime == null)
						throw new Exception("服务开始时间错误");
					if (serviceendtime == null)
						throw new Exception("服务结束时间错误");

					if (serviceendtime.compareTo(servicebegintime) < 0)
						throw new Exception("服务开始时间不能大于服务结束时间");
					// 实际工时
					BigDecimal allworktime = (new BigDecimal(
							(serviceendtime.getTime() - servicebegintime
									.getTime()) / 1000 / 60 / 60)).subtract(
							deductworkhour).setScale(2,
							BigDecimal.ROUND_HALF_UP);
					if (allworktime.intValue() < 0)
						throw new Exception("服务开始时间不能大于服务结束时间");

					// 更次
					String shiftTime = null;
					DataDict shiftDict = dictService
							.findShiftTime(servicebegintime);
					shiftTime = shiftDict.getDictid();

					DataDict amdict = dictService.findByName(accountmethodName,
							DictionaryUtils.DICT_TYPE_ACCOUNTMETHOD);
					if (amdict == null)
						throw new Exception("计费方式错误:" + accountmethodName);

					DataDict currencydict = null;
					if (ratecurrencyName.length() > 0) {
						currencydict = dictService.findByName(ratecurrencyName,
								DictionaryUtils.DICT_TYPE_CURRENCY);
						if (currencydict == null)
							currencydict = dictRmb;
					}

					Company company = companyService.findByUnique(companyName,
							"companySName");
					if (company == null)
						throw new Exception("没有找到承包商：" + companyName);

					ContractType contractType = contractTypeService
							.findByUnique(contractTypeName, "typeName");
					if (contractType == null)
						throw new Exception("没有找到合同类别:" + contractTypeName);

					Profession profession = professionService.findByUnique(
							profeName, "profename");
					if (profession == null)
						throw new Exception("没有找到工种:" + profeName);

					Station station = stationService.findByUnique(stationName,
							"station");
					if (station == null && stationName.length() > 0)
						throw new Exception("没有找到岗位:" + profeName);

					BudgetNum budgetNum = budgetNumService.findByUnique(
							budgetnumName, "budgetNum");
					if (budgetNum == null && budgetnumName.length() > 0)
						throw new Exception("没有找到预算编号:" + budgetnumName);

					Cost newvo = new Cost();
					newvo.setServicetime(shiftTime);
					newvo.setCompanyid(company.getCompanyId());
					newvo.setAccountmethod(amdict.getDictid());
					newvo.setServicedate(servicedate);
					newvo.setServicebegintime(servicebegintime);
					newvo.setServiceendtime(serviceendtime);
					newvo.setTypeid(contractType.getTypeId());
					newvo.setProfeid(profession.getProfeid());
					if (station != null)
						newvo.setStationid(station.getStationid());
					newvo.setAllworkquantity(allworkquantity);
					newvo.setAllworkhours(allworktime);
					newvo.setRate(rate);
					newvo.setDeductworkhour(deductworkhour);
					newvo.setDeductreason(deductreason);
					newvo.setRatecurrency(currencydict.getDictid());
					newvo.setUnit(unit);
					newvo.setCheckno(checknoName);
					if (budgetNum != null)
						newvo.setBudgetnum(budgetNum.getNumId());
					newvo.setRemarks(remarks);

					newvo.setCosttype(dict.getDictid());
					newvo.setStatus(dictStatus.getDictid());
					newvo.setAllcurrency(dictRmb.getDictid());
					newvo.setSource(sourceDict.getDictid());

					getBaseDao().save(newvo);
					importNum++;
				}
			}
		}
		return importNum;
	}

	/**
	 * 对一条记录进行计费
	 * 
	 * @param cost
	 * @throws Exception
	 */
	private void caculateFee(Cost cost) throws Exception {
		BigDecimal total = new BigDecimal(0);
		BigDecimal rate = cost.getRate();
		// 工作的数量或者时间数根据计费类别来取
		BigDecimal number = null;
		// 计费类型
		DataDict acdict = dictService.findById(cost.getAccountmethod());
		if (DictionaryUtils.DICT_CODE_ACCOUNTMETHOD_2.equals(acdict
				.getDatacode())) {
			number = cost.getAllworkquantity();
		} else if (DictionaryUtils.DICT_CODE_ACCOUNTMETHOD_1.equals(acdict
				.getDatacode())) {
			number = cost.getAllworkhours();
		}

		if (number == null || number.intValue() == 0)
			number = new BigDecimal(1);

		rate = cost.getRate();
		total = rate.multiply(number);
		BigDecimal currencyRat;
		// 汇率
		if (cost.getRatecurrency() != null
				&& cost.getRatecurrency().equals(cost.getAllcurrency())) {
			currencyRat = new BigDecimal(1);
		} else {
			ExchangeRate ratevo = exchangeRateService.findExchangeRate(
					cost.getServicedate(), cost.getRatecurrency(),
					cost.getAllcurrency());
			if (ratevo != null) {
				currencyRat = new BigDecimal(ratevo.getRate()).setScale(4,
						BigDecimal.ROUND_HALF_UP);
				// currencyRat.setScale(4);
			} else {
				throw new Exception("服务日期内没有找到汇率设置");
			}
		}
		total = total.multiply(currencyRat);

		cost.setAllcost(total);
	}
	
	/**
	 * 查询某月已经添加计费的数据
	 * @param companyid
	 * @param profeid
	 * @param servicedate
	 * @return
	 */
	public BigDecimal sumByMonth(Long companyid,Long profeid,Date servicedate){
		BigDecimal ret = new BigDecimal(0).setScale(3,BigDecimal.ROUND_HALF_UP);
		try {
			ret = this.getBaseDao().sumByMonth(companyid, profeid, servicedate);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ret;
	}

	@Override
	@Resource(name = "costDao")
	public void setBaseDao(ICostDao baseDao) {
		super.setBaseDao(baseDao);
	}

	public IDataDictService getDictService() {
		return dictService;
	}

	@Resource(name = "dataDictService")
	public void setDictService(IDataDictService dictService) {
		this.dictService = dictService;
	}

	public CompanyServiceImpl getCompanyService() {
		return companyService;
	}

	@Resource(name = "companyServiceImpl")
	public void setCompanyService(CompanyServiceImpl companyService) {
		this.companyService = companyService;
	}

	public IProfessionService getProfessionService() {
		return professionService;
	}

	@Resource(name = "professionService")
	public void setProfessionService(IProfessionService professionService) {
		this.professionService = professionService;
	}

	public IStationService getStationService() {
		return stationService;
	}

	@Resource(name = "stationService")
	public void setStationService(IStationService stationService) {
		this.stationService = stationService;
	}

	public ICostProfessionDao getCostProfessionDao() {
		return costProfessionDao;
	}

	@Resource(name = "costProfessionDao")
	public void setCostProfessionDao(ICostProfessionDao costProfessionDao) {
		this.costProfessionDao = costProfessionDao;
	}

	public ContractRateServiceImpl getContractRateService() {
		return contractRateService;
	}

	@Resource(name = "contractRateServiceImpl")
	public void setContractRateService(
			ContractRateServiceImpl contractRateService) {
		this.contractRateService = contractRateService;
	}

	public IPersonOrderService getPersonOrderService() {
		return personOrderService;
	}

	@Resource(name = "personOrderService")
	public void setPersonOrderService(IPersonOrderService personOrderService) {
		this.personOrderService = personOrderService;
	}

	public IExchangeRateService getExchangeRateService() {
		return exchangeRateService;
	}

	@Resource(name = "exchangeRateServiceImpl")
	public void setExchangeRateService(IExchangeRateService exchangeRateService) {
		this.exchangeRateService = exchangeRateService;
	}

	public RtgcFlOrderServiceImpl getRtgcFlOrderService() {
		return rtgcFlOrderService;
	}

	@Resource(name = "rtgcFlOrderServiceImpl")
	public void setRtgcFlOrderService(RtgcFlOrderServiceImpl rtgcFlOrderService) {
		this.rtgcFlOrderService = rtgcFlOrderService;
	}

	public IBoxContractorService getBoxContractorService() {
		return boxContractorService;
	}

	@Resource(name = "boxContractorService")
	public void setBoxContractorService(
			IBoxContractorService boxContractorService) {
		this.boxContractorService = boxContractorService;
	}

	public HolidayServiceImpl getHolidayService() {
		return holidayService;
	}

	@Resource(name = "holidayServiceImpl")
	public void setHolidayService(HolidayServiceImpl holidayService) {
		this.holidayService = holidayService;
	}

	public ContractTypeServiceImpl getContractTypeService() {
		return contractTypeService;
	}

	@Resource(name = "contractTypeServiceImpl")
	public void setContractTypeService(
			ContractTypeServiceImpl contractTypeService) {
		this.contractTypeService = contractTypeService;
	}

	public BudgetNumServiceImpl getBudgetNumService() {
		return budgetNumService;
	}

	@Resource(name = "budgetNumServiceImpl")
	public void setBudgetNumService(BudgetNumServiceImpl budgetNumService) {
		this.budgetNumService = budgetNumService;
	}
}
